package net.yegong.matrix;

import org.netlib.lapack.Ilaenv;
import org.netlib.lapack.Sgetrf;
import org.netlib.lapack.Sgetri;
import org.netlib.util.intW;

/**
 * @author cooper
 */
public class SquareMatrix extends Matrix {
	public SquareMatrix(float[] matrix, int size, MatrixType type) {
		super(matrix, size, size, type);
	}

	public SquareMatrix(int size) {
		super(size, size);
	}

	public SquareMatrix(SquareMatrix m) {
		super(MatrixHelper.copy(m.array), m.nRow, m.nCol, FORTRAN);
	}

	public static SquareMatrix toSquare(Matrix m) {
		if (m.nCol != m.nRow)
			throw new MatrixDimensionException();
		if (m instanceof SquareMatrix)
			return (SquareMatrix) m;
		return new SquareMatrix(m.array, m.nCol, FORTRAN);
	}

	/**
	 * WARNING! Before you use this method, please think in mind carefully
	 * whether you need is inversing a matrix or resolving the equations. If the
	 * latter is enough, please don't take this method. There are some
	 * comparison from matlab:
	 * <table>
	 * <tr>
	 * <td><b>inverse</b></td>
	 * <td>elapsed time: 1.4320</td>
	 * <td>errors: 7.3260e-006</td>
	 * <td>residuals: 4.7511e-007</td>
	 * </tr>
	 * <tr>
	 * <td><b>resolve</b></td>
	 * <td>elapsed time: 1.4320</td>
	 * <td>errors: 7.1209e-006</td>
	 * <td>residuals: 4.4509e-015</td>
	 * </tr>
	 * </div>
	 * 
	 * @return
	 */
	public SquareMatrix inverse() {
		float[] a = MatrixHelper.copy(array);
		int[] ipiv = new int[nRow];
		int nb = Ilaenv.ilaenv(1, "DGETRI", " ", nRow, nCol, -1, -1);
		int lwork = nRow * nb;
		float[] work = new float[lwork];
		intW info = new intW(0);
		Sgetrf.sgetrf(nRow, nRow, a, 0, nRow, ipiv, 0, info);
		Sgetri.sgetri(nRow, a, 0, nRow, ipiv, 0, work, 0, lwork, info);
		SquareMatrix ret = new SquareMatrix(a, nRow, FORTRAN);
		return ret;
	}

	@Override
	public SquareMatrix clone() {
		Matrix m = super.clone();
		return new SquareMatrix(m.array, m.nCol, FORTRAN);
	}
}
